#pragma once
#include <Rz/Object.h>
#include <Rz/IEquatable.h>
#include <Rz/ITypeWrapper.h>
#include <Rz/Collections/IEnumerable.h>

namespace Rz {

template <typename T>
class RangeIterator :
	public Object,
	public IEquatable<RangeIterator<T>>,
	public ITypeWrapper<T>
{
	public:
		RZ_RTTI(Rz, RangeIterator);
		RZ_RTTI_IMPLEMENTS(Object, IEquatable<RangeIterator<T>>, ITypeWrapper<T>);
		RZ_RTTI_TEMPLATES(NonObjectType<T>);
		RZ_RTTI_END;

		RZ_TYPEWRAPPER_IMPLEMENT(T);

		RZ_INLINE RangeIterator(T initVal, T step) : _val(initVal), _step(step) { }

		RZ_INLINE Reference operator*() { return _val; }
		RZ_INLINE Pointer operator->() { return _val; }

		RZ_INLINE RangeIterator& operator++() { _val += _step; return *this; }
		RZ_INLINE RangeIterator  operator++(int) { RangeIterator _tmp = *this; ++*this; return _tmp; }

		RZ_INLINE RangeIterator& operator--() { _val -= _step; return *this; }
		RZ_INLINE RangeIterator  operator--(int) { RangeIterator _tmp = *this; --*this; return _tmp; }

		RZ_INLINE bool operator < (const RangeIterator<T>& r) const { return r._val < _val }
		RZ_INLINE bool operator > (const RangeIterator<T>& r) const { return r._val > _val }

		RZ_INLINE bool operator <= (const RangeIterator<T>& r) const { return r._val <= _val }
		RZ_INLINE bool operator >= (const RangeIterator<T>& r) const { return r._val >= _val }

		// IEquatable
		RZ_INLINE bool Equals(const RangeIterator<T>& r) const override { return (_step > T(0) ? r._val <= _val : r._val >= _val); }
		RZ_INLINE bool operator == (const RangeIterator<T>& r) const override { return  Equals(r); }
		RZ_INLINE bool operator != (const RangeIterator<T>& r) const override { return !Equals(r); }

	private:
		T _val;
		T _step;
};

template <typename T = s32>
class Range :
	public Object,
	public Collections::IEnumerable<T, RangeIterator<T>, RangeIterator<T>>
{
	public:
		RZ_RTTI(Rz, Range);
		RZ_RTTI_IMPLEMENTS(Object, ITypeWrapper<T>);
		RZ_RTTI_TEMPLATES(NonObjectType<T>);
		RZ_RTTI_END;
                
		RZ_TYPEWRAPPER_IMPLEMENT(T);

		typedef typename Collections::IEnumerable<T, RangeIterator<T>, RangeIterator<T>>::ConstIterator ConstIterator;
		typedef typename Collections::IEnumerable<T, RangeIterator<T>, RangeIterator<T>>::Iterator		Iterator;

		Range(T to)
			: _from(T(0))
			, _to(T(to + T(to < T(0) ? -1 : 1)))
			, _step(T(to < 0 ? -1 : 1))
		{

		}

		Range(T from, T to)
			: _from(from)
			, _to(T(to + T(to < from ? -1 : 1)))
			, _step(T(to < from ? -1 : 1))
		{

		}

		Range(T from, T to, T step)
			: _from(from)
			, _to(T(to + T(to < from ? -1 : 1)))
			, _step(step)
		{

		}

		ConstIterator ConstBegin() const
		{
			return ConstIterator(_from, _step);
		}

		ConstIterator ConstEnd() const
		{
			return ConstIterator(_to, _step);
		}

		Iterator Begin()
		{
			return Iterator(_from, _step);
		}

		Iterator End()
		{
			return Iterator(_to, _step);
		}

	private:
		T _from, _to, _step;
};

}
